package com.putao.aspect;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.putao.annotation.OperateMethodName;
import com.putao.base.JwtUser;
import com.putao.constants.Constants;
import com.putao.constants.Consts;
import com.putao.domain.SysOperateLog;
import com.putao.result.JsonResult;
import com.putao.utils.RequestUtils;
import com.putao.utils.ThreadLocalUtil;
import com.putao.vo.BaseVo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class CommonAspect {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    ThreadLocal<Long> startTime = new ThreadLocal<>();


    public Object myLogger(ProceedingJoinPoint pjp, Consumer<SysOperateLog> consumer, List<String> ignoreUrls) throws Throwable {
        startTime.set(System.currentTimeMillis());
        //使用ServletRequestAttributes请求上下文获取方法更多
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (null == attributes) {
            logger.error("获取请求对象失败，直接退出方法了");
            return pjp.proceed();
        }
        HttpServletRequest request = attributes.getRequest();
        String className = pjp.getSignature().getDeclaringTypeName();
        String methodName = pjp.getSignature().getName();
        // 使用数组来获取参数  进入方法前
        Object[] array = pjp.getArgs();
        ObjectMapper mapper = new ObjectMapper();

        // 执行函数前打印日志
        // logger.info("调用前：{}：{},传递的参数为：{}", className, methodName, mapper.writeValueAsString(array));
        // logger.info("URL:{}", request.getRequestURL().toString());
        // logger.info("IP地址：{}", request.getRemoteAddr());


        // 调用整个目标函数执行 执行方法后
        Object obj = pjp.proceed();
        // 如果请求的控制器在 ignoreControllerString 包含里面，则直接跳过
//        List<String> ignoreControllerNameList = StringUtils.convertList(ignoreControllerString);
        List<String> ignoreControllerNameList = new ArrayList<>();
        String classNameNew = className.substring(className.lastIndexOf(".") + 1);
        String requestURI = request.getRequestURI();
        if (!ignoreUrls.contains(requestURI)) {
            // 从当前线程中获取用户名
            JwtUser jwtUser = ThreadLocalUtil.get();
            SysOperateLog sysOperateLog = new SysOperateLog();
            sysOperateLog.setUsername(jwtUser.getUsername());
            RequestUtils.getSystemInfo(request, sysOperateLog);
            // 从pjp中取出控制器字节码对象
            Class<?> classTarget = pjp.getTarget().getClass();
            Class<?>[] par = ((MethodSignature) pjp.getSignature()).getParameterTypes();
            // 根据字节码对象获取方法对象
            Method objMethod = classTarget.getMethod(methodName, par);
            // 根据方法对象取出注解对象
            OperateMethodName operateMethodeName = objMethod.getAnnotation(OperateMethodName.class);
            if (null == operateMethodeName) {
                // 不存在表示不记录
                return obj;
            }
            logger.error("operateMethodeName = " + operateMethodeName);
            sysOperateLog.setOperation(operateMethodeName.value());
            sysOperateLog.setTime(System.currentTimeMillis() - startTime.get() + Consts.OPERATION_TIME_UNIT);
            List<Object> objects = new ArrayList<>();
            for (Object o : array) {
                if (o instanceof BaseVo) {
                    objects.add(o);
                }
            }
            sysOperateLog.setParams(JSON.toJSONString(objects));
//            sysOperateLog.setParams(mapper.writeValueAsString(array));
            sysOperateLog.setMethod(operateMethodeName.method());
            if (obj instanceof JsonResult) {
                JsonResult<?> result = (JsonResult<?>) obj;
                sysOperateLog.setResult(result.isSuccess() ? Constants.OPERATION_RESULT_SUCCESS : Constants.OPERATION_RESULT_FAIL);
                sysOperateLog.setResultStr(JSON.toJSONString(result.getData()));
            }
            if (null != consumer) {
                consumer.accept(sysOperateLog);
            }
        }
        //执行函数后打印日志
        logger.info("调用后：{}：{},返回值为：{}", className, methodName, obj);
        logger.info("耗时：{}ms", System.currentTimeMillis() - startTime.get());
        return obj;
    }
}
